<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>JS核心语法</title>
</head>
<body>
    <script>
        //核心语法
        //变量
        //var 变量名 = 初始值  不论创建什么类型的变量  类型只有一个就是var 而具体的类型要看后面所赋予的值是什么类型的这个变量就是什么类型的
        // var num = 10;//创建了一个名为num的数字类型的变量
        // var str = 'hello';//创建了一个名为str的字符串类型的变量
        // console.log(str);
        // var arrs = [];//创建了一个名为arrs的数组(这个数组里面啥都可以放)

        //如果不初始化这个变量的话,这个变量就是一个特殊的值undefined 类型也是undefined
        //另外这个变量你在后续的改变过程中 也是可以任意改变的,既可以改为字符串,也可以改为数字...当改变成什么类型的值,这个变量也就是什么类型的变量了,
        //这样的变量类型,我们一般称为"动态类型",而像Java这样的语言显然是不支持这样的,这种一般都称为"静态类型"的,C,C++,Java,Go,Rust都是这样的
        //而这些更倾向于使用let来代替var,var是旧版本的,有很多地方是不太好的,作用域这里就有很多差别,相比下来缓释let要比var更符合直觉一些

        //JS中有几种数据类型:
        //number数字(不区分整数和浮点数) infinity表示无穷大 超出了JS最大取值 -infinity负无穷大 超出了JS最小的取值范围 NaN表示当前结果不是一个数字('hello' - 10)  (加法就是拼接) 
        //console.log('hello' - 10);

        // let a = true;
        // console.log(a + 1);
        //boolean类型 (true为真,false 为假)   这里的是被当成1和0来使用的 true会被当成1来进行处理,这样的设定方式被称为"隐式类型转换,
        //小知识:如果一个编译语言,支持隐式类型转换,认为类型越弱  反之...   静态类型和动态类型  和强类型 弱类型是不一样的 
        
        //string字符串类型(不区分字符串和字符) 和java是基本类似的
        //由于这里的字符串不区分单双引号 因此如果一个字符串中有其他单双引号,外面单引号里面可以使用双引号,外面单引号里面可以使用双引号,
        //如果一定要在双引号内部使用双引号的话 一定是要进行转义的\"类似于这样,单引号也是一样的,而且转义字符也有很多种\t,\n,\f......都是支持的 
        //求字符串的长度通过length来得到 s.length就可以获得长度 而且这里的长度是按字符来进行计算的,一个汉字也是一个字符,另外字符串中也有很多的方法可以使用
        // let s = "hello";
        // console.log(s.length);
        // let s2 = "哈哈";
        // console.log(s2.length);
        
        // var w;
        // console.log(w);
        //undefined 唯一的值表示未定义的值   未初始的变量,这个变量就是一个特殊的值undefined 类型也是undefined  
        //这个类型和null是不一样的这表示非法情况,而null是合法的
        //null唯一的值,表示空值



        //运算符
        //在JS中 ==和!= 表示只比较两个变量的值,如果一个变量通过隐式类型转换可以得到另一个值那么这两个值就是相等的
        //=== 和!== 表示既要比较两个变量的值,又要比较两个变量的类型,如果类型不同也就不同了
        // console.log(10 == '10');
        // console.log(10 === '10');
        //而说道比较 有三个维度的比较1.比较身份(是否为同一个对象) 2.比较值(对象里面存储的是否相同) 3.比较类型(两个对象是否是同一个类型)

        //&&和|| 也和Java是不一样的 
        //在java中 &&和|| 就返回一个布尔类型 true或者false
        //而在JS中&&和|| 会返回其中一个表达式的值
        //例如 c = a || b  如果a的值为真(非0),就会返回a的值,也就是c此时的值就是a的值,如果a的值为假,就会返回b的值,也就是c此时的值就是b的值
        //c = a && b  如果a的值为真(非0),就会返回b的值,也就是c此时的值就是a的值,如果a的值为假,就会返回a的值,也就是c此时的值就是a的值  就相当于只看前面一个值的结果就可以确定了
        //而这样就衍生出了JS的一种习惯用法 判断一个变量是否为空值 ,如果是空值就会赋予一个新的值:a = a || 0;

        // JS的/和Java的也不太一样 js中不区分整数小数 因此1/2结果就是0.5而不是0

        //if else 和Java差不多  if里面的语句  三元表达式也是一样的 switch也是一样的
        // if(0){
        //     console.log("hh");
        // }else{
        //     console.log("hai");
        // }

        //while 和for循环也都是一样的

        //数组  JS的数组和Java的区别还是很大的
        //数组的创建: 
        // let arr = new Array();
        // let arr2 = [];
        
        //而且在JS数组中可以放任何类型(包括数组也可以)的数组   不能强制要求里面只能放一种类型
        //要打印数组的话直接通过log就可以打印了
        // let arr = [1,2,3,'hello'];
        // console.log(arr);
        // arr.splice(1,2,'hi');
        // console.log(arr);
        
        // console.log(arr.length);
        // arr.length = 3;
        // console.log(arr);
        // console.log(arr.length);
        // arr.hello1 = 203;
        // //arr[100] = 10;
        // arr[-1] = 10;
        // arr['hello'] = 20;
        // console.log(arr);
        // console.log(arr[100]);
        // console.log(arr[1]);
        // console.log(arr[2]);
        // console.log(arr[3]);

        //获取数组元素,下标也是从0开始计算的
        // console.log(arr3[0]);
        //而如果访问一个超出数组下标的值 是不会出现 数组越界异常的 而是会得到undefined arr3[100]
        //以下操作  非礼勿视:
        // arr3[100] = 10;//这样非但不会报错,而且会得到一个更大的数组 前面有的元素还是不变的 ,而下标为100的值就是锁赋予的值,而中间的所有值都是空属性的也就是undefined
        // arr3[-1] = 10;//这样的操作也是不会报错的,此时的-1与其说是一个下标,不如说是一个'属性',这样的一一对应更像是一个键值对 放在了这个数组里面,而且这样的操作不会影响数组的长度
        // arr3['hello'] = 10;//这个也是可以的 ,就像上面说的键值对一样
        //JS中的数组  与其说是一个数组 其更像是一个map,更准确的说这是一个对象,而且是可以在运行是=时,给对象新增属性的,arr3['hello'] = 10;就像是给这个数组了一个属性,属性名字为hello,属性的值为10
        //上面这些操作之所以会感到差异 主要还是"静态类型"和"动态类型"两个流派的碰撞

        //获取数组长度通过.length就可以    而且而且这个length是可以改的  假设原本为4 改成3就会删除掉最后一个元素  改成5就会多一个空属性(undefined)
        //给数组插入元素:最常见的就是push方法,类似于(ArrayList中的add方法)
        //删除数组中的元素:splice 准确来说是针对数组中的某个片段,进行替换(既可以用来插入元素,也可以用来删除元素)
        // let arr4 = [1,2,3,4];
        // arr.splice(1,2,'hello');//第一个参数是起始位置,第二个参数表示多少个(从起始位置开始),后面的则为要替换的值(不写就表示删除)
        //另外数组中也是有很多的方法的,这里就不具体介绍了
        



        //在JS中是函数(function)而在Java中叫做方法(method)  这两个其实是同一个东西,通常情况下不去考量这两个概念的区别,但是如果非要考量,可以这样理解:
        //函数式和对象独立开来的代码片段,而方法则是一拖一对象的代码片段,方法可以理解为成员函数
        // 函数包括定义和调用
        // function 函数名(形参列表){ 这里是不必写返回值类型的,而且形参列表里面也不用写具体的类型其实都是let类型的
        //     函数实体
        //     return 返回值
        // }
        // function add(x,y){
        //     return x + y;
        // }
        // let num = add(10,20);
        // console.log(num);
        // let num1 = add('hello',27);
        // console.log(num1);//各种参数都是可以的只要能进行这种运算就可以

        //一般需要调用时传入的实参,个数和类型都是匹配的,但是实际上,JS并没有做出这样的限制,因此多个参数也不是不行的
        //例如多个参数:
        // function add1(a,b,c,d,e,f,g){
        //     a = a || 0;
        //     b = b || 0;
        //     c = c || 0;
        //     d = d || 0;
        //     e = e || 0;
        //     f = f || 0;
        //     g = g || 0;


        //     return a + b + c + d + e + f + g;
        // }
        // console.log(add1(10,20));
        // console.log(add1(10,20,30));
        // console.log(add1(10,20,30,40));
        //这样写虽然没有报错但是其得到的结果不是一个整数是NaN,因为没有传入的参数此时是undefined,因此还需要加以修改,这就用到了,前面讲过的判断一个变量是否为空值的语句
        //如果实参比形参多了多出来的实参其实就没了,函数内部就拿不到了   这样的设定其实是JS的专属属性(所以我们自己写的时候尽量还是保证形参和实参的个数能够匹配,不会出现这样的问题,保证严谨性)
        
        //一个新的概念:函数表达式: 在JS中,函数是"一等公民"(函数就像一个普通的变量一样,可以被赋值给其他的变量,也可以作为另一个函数的参数,还可以作为另一个函数的返回值(这一般就被称为一等公民))
        //而这里的函数表达式其实就是把一个函数赋值给一个变量
        //例如:
        // function a(){
        //     console.log("a");
        // }
        // let f = a;//此时a作为一个函数,后面没有带括号,这就是一个赋值操作,而不是函数调用
        // f();//然后通过这个变量我们也可以调用这个函数
        // //合并:
        // let f1 = function (){//这样后面就可以基于f这个变量,来调用这个函数了  而这个函数其实就是我们之前所学到的lambda表达式
        //     console.log("a");
        // }




        //作用域  :ES6是JS的版本就相当于Java的1.8版本 地位也是差不多的,最经典的版本
        //在ES6之前其实是只有全局作用域和函数作用域的概念而没有块级作用域(var搞的鬼) 而在ES6之后JS引入了let然后就有了块级作用域这个概念,但是块级作用域是{}内部无法访问到{}外部的,而在JS中这是可以做到的
        // let num = 0;
        // {
        //     console.log(num);//这其实是可以做到的
        // }
        //另外
        // let num = 0;
        // function hello(){
        //     console.log(num);
        // }
        
        // hello();//这其实也是可以的
        //在JS中的作用域是支持"逐级向上"查找的, 当在函数中尝试找到这个变量,但是函数中没有,就会往上寻找(支持无线套娃),找到外面,直到找到全局变量作用域,还是没找到的话就会报错了
        //这其实就是一个作用域链,而如果在作用域链不同节点上存在多个同名的变量,这是会从内向外找,找到第一个就结束(而如果想找到全局变量的这个变量可以使用window.变量 来找,不过这样的操作还是做好用传参来找比较靠谱)
        // let num = 10;
        // function hello(){
        //     function hello1(){
        //         console.log(num);
        //     }
        //     hello1();
        // }
        // hello();




        //对象  对象就是一些属性和方法的集合  在Java中一般对象是依托于类的,有了类通过类的实例化才可以产生对象,而在JS中对象是不依托于类的 ,在JS所有的类都是一个类型 Object类型
        //而创建对象就直接通过{}就可以了
        //例如: 每个属性和方法就是通过键值对的方式来表达的(就像json一样)
        // let student = {
        //     name: '张三',
        //     age: 20,
        //     weight: 130,
        //     height: 175,
        //     eat: function (){
        //         console.log("吃饭");
        //     },
        //     sleep: function(){
        //         console.log("睡觉");
        //     },
        // };
        // console.log(student.name);
        // console.log(student.age);
        // console.log(student.weight);
        // console.log(student.height);
        // console.log(student.eat);
        // console.log(student.sleep);


        //然后通过类名.属性 就可以进行访问了
        //在JS中一个对象有哪些成员,也是可以动态改变的

        //JS中也是有一些现成的对象的,像数组,本质上就可以视为是一个对象,而JS虽然有对象,但是JS不算是一个面向对象的变成语言,因为其并没有封装继承(其实在JS中有一个"原型"其实可以实现,但是也是和Java中有差别的) 多态的面向对象的特征
        
</script>

    <!-- <script>
        console.log("hello log");
    </script> -->


    <script>
        //内嵌式
        // alert("hello");
    </script>
    <!-- <button onclick="alert('hello 2')">行内式</button> -->
    <!-- <script src="c.js">
        //外部式
    </script> -->
</body>
</html>